/*
 * @(#) Resource.java
 *
 * Copyright 2006 - 2009 by the original authors of Galaxy
 * and all its contributors ("Galaxy.org").
 *
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kyodai;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Image;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreFullException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;

/**
 * A resource handler for application.
 *
 * @author Cheng Liang
 * @version 1.0
 */
public class Resource {
	
	// record name
	/**
	 * High score record name of easy level.
	 */
	public static final String HIGH_SCORE_EASY = "HIGH_SCORE_EASY";
	
	/**
	 * High score record name of normal level.
	 */
	public static final String HIGH_SCORE_NORMAL = "HIGH_SCORE_NORMAL";
	
	/**
	 * High scroe record name of hard level.
	 */
	public static final String HIGH_SCORE_HARD = "HIGH_SCORE_HARD";

	// application state
	public static final int SPLASH_SCREEN = 0;
	public static final int MENU_SCREEN = 1;
	public static final int HELP_SCREEN = 2;
	public static final int ABOUT_SCREEN = 3;
	public static final int CONFIG_SCREEN = 4;
	public static final int PLAY_SCREEN = 5;
	public static final int HIGH_SCORE_SCREEN = 6;
	public static final int LOAD_SCREEN = 7;
	public static final int EXIT_GAME = 8;
	public static final int SOUND_SCREEN = 9;
    // game type
    public static final int GAME_WIN = 101;
    public static final int GAME_PAUSE = 103;
    public static final int GAME_LOSE_TIME_OUT = 104;
    public static final int GAME_LOSE_RESET_OVER = 105;
    public static final int GAME_ALERT = 106;
	
    // game time
    public static final int TOTAL_TIME = 1280;
    // game level
    public static final int EASY = 0;
    public static final int NORMAL = 1;
    public static final int HARD = 2;
    // key mask
    private static int offset = 0;
    public static final int KEY_UP = 1 << ++offset;
    public static final int KEY_UP_FLAG = 1 << ++offset;
    public static final int KEY_LEFT = 1 << ++offset;
    public static final int KEY_LEFT_FLAG = 1 << ++offset;
    public static final int KEY_DOWN = 1 << ++offset;
    public static final int KEY_DOWN_FLAG = 1 << ++offset;
    public static final int KEY_RIGHT = 1 << ++offset;
    public static final int KEY_RIGHT_FLAG = 1 << ++offset;
    public static final int KEY_OK = 1 << ++offset;
    public static final int KEY_OK_FLAG = 1 << ++offset;
    public static final int KEY_HINT = 1 << ++offset;
    public static final int KEY_HINT_FLAG = 1 << ++offset;
    public static final int KEY_RESET = 1 << ++offset;
    public static final int KEY_RESET_FLAG = 1 << ++offset;
    public static final int KEY_MENU = 1 << ++offset;
    public static final int KEY_MENU_FLAG = 1 << ++offset;

    /**
     * Mono space bold large font.
     */
    public static final Font FONT_MONO_BOLD_LARGE = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE);
    
    /**
     * Mono space bold small font.
     */
    public static final Font FONT_MONO_BOLD_SMALL = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_SMALL);
    
    private static final Resource res = new Resource();
    private static final Random rand = new Random();
    private static Player soundPlayer;
    
    public static Resource getInstance() {
    	return res;
    }

    /**
     * Creates an image from resource file using file name "name".
     *
     * @param name image file name
     * @return created image, null if no such file or exception happens
     */
    public Image createImage(String name) {
        try {
            return Image.createImage(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * Gets a random integer between 0 and range(not include).
     *
     * @param range top of the random integer
     */
    public int nextInt(int range) {
    	return rand.nextInt(range);
    }
    
    /**
     * Starts background sound.
     */
    public void startBackgroundSound() {
		if(soundPlayer == null) {
			soundPlayer = create("/bg.mid", "audio/midi");
		}
		start(soundPlayer);
	}
	
    /**
     * Stops background sound.
     */
	public void stopBackgroundSound() {
		if(soundPlayer != null) {
			try {
				soundPlayer.stop();
				soundPlayer = null;
			} catch (MediaException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Sets a new high score record. If there is no such a record named 
	 * {@code recordName}, a new record will be created; otherwise, the record 
	 * will be updated.
	 * 
	 * @param recordName record to created or update, this parameter should be
	 * valued among Resource.HIGH_SCORE_EASY, Resource.HIGH_SCORE_NORMAL and 
	 * Rescource.HIGH_SCORE_HARD.
	 */
	public void setHighScore(String recordName) {
		RecordStore rs = null;
		ByteArrayOutputStream baos = null;
		DataOutputStream dos = null;
		try {
			rs = RecordStore.openRecordStore(recordName, true);
			baos = new ByteArrayOutputStream();
			dos = new DataOutputStream(baos);
//			dos.write(b); FIXME write something
			byte[] record = baos.toByteArray();
			if(rs.getNumRecords() == 0) {
				rs.addRecord(record, 0, record.length);
			} else {
				rs.setRecord(1, record, 0, record.length);
			}
		} catch (RecordStoreFullException e) {
			e.printStackTrace();
		} catch (RecordStoreNotFoundException e) {
			e.printStackTrace();
		} catch (RecordStoreException e) {
			e.printStackTrace();
		} finally {
			if(dos != null) {
				try {
					dos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(baos != null) {
				try {
					baos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(rs != null) {
				try {
					rs.closeRecordStore();
				} catch (RecordStoreNotOpenException e) {
					e.printStackTrace();
				} catch (RecordStoreException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * Loads a high score record. If there is no such a record named 
	 * {@code recordName}, nothing will do; otherwise, the record data will be
	 * loaded.
	 * 
	 * @param recordName record to created or update, this parameter should be
	 * valued among Resource.HIGH_SCORE_EASY, Resource.HIGH_SCORE_NORMAL and 
	 * Rescource.HIGH_SCORE_HARD.
	 */
	public void loadHighScore(String recordName) {
		RecordStore rs = null;
		ByteArrayInputStream bais = null;
		DataInputStream dis = null;
		try {
			rs = RecordStore.openRecordStore(recordName, false);
			if(rs == null) {
				return;
			}
			byte[] record = rs.getRecord(1);
			bais = new ByteArrayInputStream(record);
			dis = new DataInputStream(bais);
			//dis.readByte(); FIXME read something
		} catch (RecordStoreFullException e) {
			e.printStackTrace();
		} catch (RecordStoreNotFoundException e) {
			e.printStackTrace();
		} catch (RecordStoreException e) {
			e.printStackTrace();
		} finally {
			if(dis != null) {
				try {
					dis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(bais != null) {
				try {
					bais.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(rs != null) {
				try {
					rs.closeRecordStore();
				} catch (RecordStoreNotOpenException e) {
					e.printStackTrace();
				} catch (RecordStoreException e) {
					e.printStackTrace();
				}
			}
		}
	}
    
    private Player create(String fileName, String format) {
		Player player = null;
		InputStream is = Resource.class.getResourceAsStream(fileName);
		try {
			player = Manager.createPlayer(is, format);
			player.prefetch();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MediaException e) {
			e.printStackTrace();
		}
		return player;
	}
	
	private void start(Player player) {
		if(player != null) {
			try {
				player.stop();
				player.setMediaTime(0L);
				player.setLoopCount(-1);
				player.start();
			} catch (MediaException e) {
				e.printStackTrace();
			}
		}
	}
	
	private Resource() {
	}
	
}
